//
//  Register.m
//  iCan - iPhone Context-Aware Navigation
//  Carnegie Mellon University - 18-842 Distributed Systems
//
//  Created by Andrew Santell on 3/26/12.
//  Copyright (c) 2012 Andrew Santell. All rights reserved.

/* View Controller to allow users to register an account on the iCan network */

#import "Register.h"
#import "NSDataEncryption.h"
#import "Base64.h"

@interface Register ()

@end

@implementation Register
@synthesize picker;
@synthesize groupArray;
@synthesize userText;
@synthesize passText;
@synthesize firstText;
@synthesize lastText;
@synthesize groupText;
@synthesize home;
@synthesize message, result;
@synthesize inputStream, outputStream;
@synthesize appDelegate;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    appDelegate = [[UIApplication sharedApplication] delegate];
    
    /* Setup Picker Data */
    groupArray = [[NSMutableArray alloc] init];
    [groupArray addObject:@"Guest"];
    [groupArray addObject:@"Faculty"];
    [groupArray addObject:@"Staff"];
    [groupArray addObject:@"Student"]; 
    
    groupText.inputView = picker;
    picker.frame = CGRectMake(500, 500, 130, 162);
}

- (void)viewDidUnload
{
    [self setPicker:nil];
    [self setUserText:nil];
    [self setPassText:nil];
    [self setFirstText:nil];
    [self setLastText:nil];
    [self setGroupText:nil];
    [self setHome:nil];
    [self setResult:nil];
    [self setGroupArray:nil];
    [self setMessage:nil];
    [self setAppDelegate:nil];
    [self setInputStream:nil];
    [self setOutputStream:nil]; 
    [super viewDidUnload];

}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
    return 1;
}

-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
    return [groupArray count];
}

-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
    return [groupArray objectAtIndex:row];
}

- (void) pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
    groupText.text = [groupArray objectAtIndex:row];
    [groupText resignFirstResponder];
}

- (BOOL)textFieldShouldReturn:(UITextField *)theTextField 
{
    [theTextField resignFirstResponder];
    return YES;
}

- (IBAction)register:(id)sender 
{
    /* Bounds checking on User Input */
    NSCharacterSet *charSet = [NSCharacterSet alphanumericCharacterSet];
    BOOL validUser = [[userText.text stringByTrimmingCharactersInSet:charSet] isEqualToString:@""];
    BOOL validFirst = [[firstText.text stringByTrimmingCharactersInSet:charSet] isEqualToString:@""];
    BOOL validLast = [[lastText.text stringByTrimmingCharactersInSet:charSet] isEqualToString:@""];

    UIAlertView *invalidChar = [[UIAlertView alloc] initWithTitle:@"Error" message:@"You have entered invalid characters or an invalid length. Please use different data."delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];

    if ((validUser == FALSE) || (userText.text.length > 20) || (userText.text.length == 0))
    {
        [invalidChar show];
    }   
    else if ((validFirst == FALSE) || (firstText.text.length > 20) || (firstText.text.length == 0))
    {
        [invalidChar show];
    }
    else if ((validLast == FALSE) || (lastText.text.length > 20) || (lastText.text.length == 0))
    {       
        [invalidChar show];
    }
    else if ((passText.text.length > 20) || (passText.text.length == 0))
    {    
        [invalidChar show];
    } 
    else if (groupText.text.length == 0)
    {
        [invalidChar show];
    }
    else
    {
        /* Disable Back button while connecting to network */
        home.enabled = NO;
        
        NSString *sanitizedPassword = [passText.text stringByReplacingOccurrencesOfString:@";" withString:@"%42"];
        
        /*Populate message to send to server */
        message = userText.text;
        message = [message stringByAppendingString:@";"];
        message = [message stringByAppendingString:sanitizedPassword];
        message = [message stringByAppendingString:@";"];
        message = [message stringByAppendingString:firstText.text];
        message = [message stringByAppendingString:@";"];
        message = [message stringByAppendingString:lastText.text];
        message = [message stringByAppendingString:@";"];
        message = [message stringByAppendingString:groupText.text];
        message = [message stringByAppendingString:@";"];
        message = [message stringByAppendingString:@"\n"];

        /* Initiate network connection */
        [self initNetworkCommunication];
    }
}

- (void) analyzeResult
{
    /* Set up alert for errors */
    UIAlertView *badAlert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"We are unable to register your account.  Please try again."delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
    UIAlertView *goodAlert = [[UIAlertView alloc] initWithTitle:@"Success!" message:@"You have successfully registered an account!"delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
    UIAlertView *takenAlert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"The user name you have selected is not available. Please try again."delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
    
    /* The server responds ACK on success and NACK on error */
    NSLog(@"result = %@", result);
    
    if ([result isEqualToString:@"ACK"])
    {
        [goodAlert show];
    }
    else if([result isEqualToString:@"TAKEN"])
    {
        [takenAlert show];
    }
    else 
    {
        [badAlert show];
    }
    result = NULL;  

}

/* Initiate network connection */
- (void) initNetworkCommunication
{
    
    CFReadStreamRef readStream = NULL;
    CFWriteStreamRef writeStream = NULL;
    CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)appDelegate.authIP, appDelegate.authPort, &readStream, &writeStream);
    
    inputStream = (__bridge NSInputStream *) readStream;
    outputStream = (__bridge NSOutputStream *) writeStream;
    
    [inputStream setDelegate:self];
    [outputStream setDelegate:self];
    
    /* Put input and output streams into a run loop */
    [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    
    [inputStream open];
    [outputStream open];
    
    /* Encode function in base64 */
    NSData *data = [[NSData alloc] initWithData:[message dataUsingEncoding:NSASCIIStringEncoding]];
    NSString *b64;
    Base64 *b64Obj = [[Base64 alloc] init];
    b64 = [b64Obj Base64Encode:data];
  
    /* Add function name to beginning of base64 so it is sent in clear.  Convert to data before sending over wire*/
    NSString *sendString = [@"register_user;" stringByAppendingString:b64];
    NSData *sendData = [[NSData alloc] initWithData:[sendString dataUsingEncoding:NSASCIIStringEncoding]];
    
    /* Send message to network */
    [outputStream write:[sendData bytes] maxLength:[sendData length]];
    
    
   /* 
    AES Encryption doesn't work.  Problems with converting between NSString to NSData and differnt encodings
    
    int low = 0;
    int len = 16;
    NSString *preEncrypt;
    NSMutableData *tempEncryption;
    NSString *pass = @"tartans@1";
    NSString *encryptedString = @"";
    
     Encrypt data before sending across wire.  Must be in 16 byte blocks to be compatible with PyCrypto
    while ((low + len) < message.length)
    {
        preEncrypt = [message substringWithRange:NSMakeRange(low, len)];
        NSData *tempData = [preEncrypt dataUsingEncoding:NSASCIIStringEncoding];
        NSLog(@"temp data = %@", tempData);
        tempEncryption = (NSMutableData *) [tempData AES256EncryptWithKey:pass];
        encryptedString = [encryptedString stringByAppendingString:[[NSString alloc] initWithData:tempEncryption encoding:NSASCIIStringEncoding]];
        low += 16;
    NSLog(@"encrypted string (loop) = %@", encryptedString);
    }

    
    if (!(message.length - 1) < low)
    {
        preEncrypt = [message substringWithRange:NSMakeRange(low, (message.length - low - 1))];

        NSData *tempData = [preEncrypt dataUsingEncoding:NSASCIIStringEncoding];
        tempEncryption = (NSMutableData *) [tempData AES256EncryptWithKey:pass];
        encryptedString = [encryptedString stringByAppendingString:[[NSString alloc] initWithData:tempEncryption encoding:NSASCIIStringEncoding]];
        NSLog(@"loop");
    }
    
    NSLog(@"encrypted string = %@", encryptedString); 
    NSData *tempData = [[NSData alloc] initWithData:[encryptedString dataUsingEncoding:NSUTF8StringEncoding]];
    
     NSData *sendData1 = [sendString dataUsingEncoding:NSASCIIStringEncoding];
     NSLog(@"senddata1 = %@", sendData1); */
}

- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent 
{
    /* Create error popup for failed connections */
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Could not connect to host"delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
    
    switch (streamEvent) 
    {
		case NSStreamEventOpenCompleted:
			NSLog(@"Stream opened");
			break;
            
        /* Accept return message from network */
		case NSStreamEventHasBytesAvailable:
            
            if (theStream == inputStream) 
            {
                
                uint8_t buffer[1024];
                int len;
                
                while ([inputStream hasBytesAvailable]) 
                {
                    len = [inputStream read:buffer maxLength:sizeof(buffer)];
                    if (len > 0) 
                    {
                        
                        result = [[NSString alloc] initWithBytes:buffer length:len encoding:NSASCIIStringEncoding];
                        
                        if (nil != result) 
                        {
                            NSLog(@"Response: %@", result);
                            
                        }
                    }
                }
            }
			break;			
            
		case NSStreamEventErrorOccurred:
            
            NSLog(@"Can not connect to the host!");
            NSLog(@"Error Result (Should be NULL) = %@", result);
            [inputStream close];
            [inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            [outputStream close];
            [outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            [alert show];
            /* Enable Back Button again */
            home.enabled = YES;
			break;
            
		case NSStreamEventEndEncountered:
            NSLog(@"Closing Connection");
            [inputStream close];
            [inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            [outputStream close];
            [outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            home.enabled = YES;
            [self analyzeResult];
			break;
            
		case NSStreamEventHasSpaceAvailable:
            NSLog (@"Output Buffer is Empty");
            break;
            
        default:
			NSLog(@"Unknown event");
            NSLog(@"Error Result (Should be NULL) = %@", result);
            [inputStream close];
            [inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            [outputStream close];
            [outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            home.enabled = YES;
            [alert show];
	}
}

@end